﻿// Necroz project team © <2015> <ArchLord2EMU>
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Author:Sagara
// Date:2015-09-06-23:29

using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using ArchLord2Commons.IoC.Interfaces;
using NLog;

namespace ArchLord2Commons.IoC
{
    public abstract class Global
    {
        private static readonly Logger Log = LogManager.GetCurrentClassLogger();

        public static readonly ConcurrentDictionary<IGlobalDynamicMember, Type> DinamycDictionary = new ConcurrentDictionary<IGlobalDynamicMember, Type>();
        public static readonly ConcurrentDictionary<IGlobalMember, Type> StaticDictionary = new ConcurrentDictionary<IGlobalMember, Type>();

        private static readonly object Lock = new object();

        /// <summary>
        /// Global thread
        /// </summary>
        private static Thread Instance { get; set; }
        /// <summary>
        /// Is work flag
        /// </summary>
        public static bool IsWork;
        /// <summary>
        /// Global instance, start initilize
        /// </summary> 
        public static void Initilize()
        {
            IsWork = true;
            Instance = new Thread(() =>
            {
                while (true)
                {
                    lock (Lock)
                        foreach (var type in DinamycDictionary.Keys)
                            type.Action();

                    if (!IsWork)
                    {
                        DisposeAllMembers();
                        break;
                    }
                    Thread.Sleep(1);
                }
            });

            if (IsWork)
                Instance.Start();

            AppDomain.CurrentDomain.UnhandledException +=
                (sender, eventArgs) =>
                {
                    Log.Error("Unknown exception was occured in object {0}!", eventArgs.ExceptionObject.GetType().Name);
                    IsWork = false;
                };

            Console.CancelKeyPress +=
                (sender, eventArgs) =>
                {
                    Log.Info("Cancel event invoke...");
                    DisposeAllMembers();
                    IsWork = false;
                };
        }
        /// <summary>
        /// Release all types on collection`s
        /// </summary>
        private static void DisposeAllMembers()
        {
            foreach (var type in DinamycDictionary.Keys)
                type.Release();

            foreach (var type in StaticDictionary.Keys)
                type.Release();
        }
        /// <summary>
        /// Register class on IoC for next checking
        /// </summary>
        /// <param name="type"></param>
        public static void Register(IGlobalDynamicMember type)
        {
            var ctype = (IGlobalDynamicMember)Activator.CreateInstance(type.GetType());
            DinamycDictionary.TryAdd(type, ctype.GetType());

            ctype.Initilize();
        }
        /// <summary>
        /// Register class on IoC
        /// </summary>
        /// <param name="type"></param>
        public static void Register(IGlobalMember type)
        {
            var ctype = (IGlobalMember)Activator.CreateInstance(type.GetType());
            StaticDictionary.TryAdd(type, ctype.GetType());
            ctype.Initilize();
        }
        /// <summary>
        /// Get class from IoC
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetMember<T>() where T : IGlobalMember
        {
            foreach (IGlobalMember member in StaticDictionary.Keys.Where(member => member.GetType().GetInterfaces().Contains(typeof(T))))
                return (T)member;

            return default(T);
        }
        /// <summary>
        /// Get class from IoC
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetDMember<T>() where T : IGlobalDynamicMember
        {
            foreach (IGlobalDynamicMember member in DinamycDictionary.Keys.Where(member => member.GetType().GetInterfaces().Contains(typeof(T))))
                return (T)member;

            return default(T);
        }
        /// <summary>
        /// Unregister class member
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void UnregisterMember<T>() where T : IGlobalMember
        {
            Type toOut;
            foreach (IGlobalMember member in StaticDictionary.Keys.Where(member => member.GetType().GetInterfaces().Contains(typeof(T))))
                StaticDictionary.TryRemove(member, out toOut);
        }
        /// <summary>
        /// Unregister class member
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void UnregisterDMember<T>() where T : IGlobalDynamicMember
        {
            Type toOut;
            foreach (IGlobalDynamicMember member in DinamycDictionary.Keys.Where(member => member.GetType().GetInterfaces().Contains(typeof(T))))
                DinamycDictionary.TryRemove(member, out toOut);
        }
    }
}
